using System;
using NFreeMarker.Template;
using Number = NFreeMarker.Template.Utility.Number;

namespace NFreeMarker.Core
{
    internal sealed class UnaryPlusMinusExpression : Expression
    {
        private readonly Expression _target;
        private readonly bool _isMinus;
        private readonly Number.IntNumber _minusOne = new Number.IntNumber(-1);

        internal UnaryPlusMinusExpression(Expression target, bool isMinus)
        {
            _target = target;
            _isMinus = isMinus;
        }

        protected override ITemplateModel _getAsTemplateModel(Environment env)
        {
            ITemplateNumberModel targetModel;
            try
            {
                targetModel = (ITemplateNumberModel) _target.GetAsTemplateModel(env);
            }
            catch (InvalidCastException)
            {
                string msg = "Error " + GetStartLocation();
                msg += "\nExpression " + _target + " is not numerical.";
                throw new NonNumericalException(msg, env);
            }
            if (!_isMinus)
            {
                return targetModel;
            }
            Number n = targetModel.GetAsNumber();
            n = ArithmeticEngine.ConservativeEngine.Multiply(_minusOne, n);
            return new SimpleNumber(n);
        }

        public override string GetCanonicalForm()
        {
            string op = _isMinus ? "-" : "+";
            return op + _target.GetCanonicalForm();
        }

        internal override bool IsLiteral()
        {
            return _target.IsLiteral();
        }

        protected override Expression DeepCloneImpl(string name, Expression subst)
        {
            return new UnaryPlusMinusExpression(_target.DeepClone(name, subst), _isMinus);
        }
    }
}